﻿#region

using System;
using System.IO;
using System.Reflection;
using DomainModel.Domain.Model;
using DomainModel.Domain.Model.MessageAssemblyModel;
using DomainModel.Domain.Model.MessageTypeModel;
using DomainModel.Domain.Model.ServiceModel;
using DomainModel.Utils;
using EsbMonitor.Ninject;
using EsbMonitorMessages.Events;
using Iesi.Collections.Generic;
using MessageTypeDescriber.Xml;
using NServiceBus;

#endregion

namespace EsbMonitor.Handlers
{
    public class MessageAssemblyLoadedEventHandler : IHandleMessages<IMessageAssemblyLoaded>
    {
        public IBus Bus { get; set; }

        public void Handle(IMessageAssemblyLoaded message)
        {
            var servicesRepository = KernelContainer.Get<IServicesRepository>();
            QueueInfo queueInfo = new QueueInfo(message.ServiceInfo.InputQueue.QueueName);
            Service service = servicesRepository.Get(queueInfo);

            if (service == null)
            {
                Bus.HandleCurrentMessageLater();
                return;
            }

            var messageAssembliesRepository = KernelContainer.Get<IMessageAssembliesRepository>();
            var md5Hasher = KernelContainer.Get<IMd5Hasher>();

            string hash = md5Hasher.Md5(message.BinaryData);

            MessageAssembly messageAssembly = messageAssembliesRepository.Get(hash);

            if (messageAssembly == null)
            {
                string path = @"d:\temp\esb\" + hash + ".dll";

                File.WriteAllBytes(path, message.BinaryData);

                Console.WriteLine("saved file " + path);

                messageAssembly = new MessageAssembly(messageAssembliesRepository.NextMessageAssemblyId())
                                      {
                                          Name = message.MessageAssemblyInfo.MessageAssemblyName,
                                          FileName = message.FileName,
                                          FileSize = message.BinaryData.Length,
                                          LocalName = path,
                                          Hash = hash                                          
                                      };

                var messageTypes = StoreTypesFromMessageAssembly(message.BinaryData);

                foreach (var m in messageTypes)
                {
                    Console.WriteLine("messageType.id: " + m.Id);
                }

                foreach (var messaageType in messageTypes)
                {
                    messageAssembly.AddMessageType(messaageType);                    
                }

                Console.WriteLine("    ----- ");

                foreach (var m in messageAssembly.MessageTypesList)
                {
                    Console.WriteLine("messageAssembly.MessageTypesList.id: " + m.Id);
                }

                messageAssembliesRepository.Store(messageAssembly);

                
            }

           service.AddMessageAssembly(messageAssembly);

            servicesRepository.Store(service);
        }

        private ISet<MessageType> StoreTypesFromMessageAssembly(byte[] rawAssembly)
        {
            Assembly assembly = Assembly.Load(rawAssembly);

            ISet<MessageType> messageTypesSet = new HashedSet<MessageType>();

            foreach (var type in assembly.GetTypes())
            {
               MessageType messageType = StoreType(type);
                messageTypesSet.Add(messageType);
            }

            return messageTypesSet;
        }

        private MessageType StoreType(Type type)
        {
            var messageTypesRepository = KernelContainer.Get<IMessageTypesRepository>();
            var md5Hasher = KernelContainer.Get<IMd5Hasher>();

            var typeDescription = new TypeFullDescription(type);
            string xml = TypeFullDescription.ToXml(typeDescription);
            string hash = md5Hasher.Md5(xml);

            MessageType messageType = messageTypesRepository.Get(hash);

            if (messageType == null)
            {
                messageType = new MessageType(messageTypesRepository.NextMessageTypeId())
                                  {
                                      Hash = hash,
                                      Name = type.FullName,
                                      TypeDescription = {TypeFullDescription = typeDescription}
                                  };

                messageTypesRepository.Store(messageType);
            }

            return messageType;
        }
    }
}